﻿using System;
using System.Collections.Generic;
using System.IO;

namespace Algorytm
{
    public class Algorytm_Tworzenie_dla_Szkoly
    {
        int liczba_nauczycieli;
        int liczba_przedmiotow;
        static public int liczba_klas;
        int liczba_sal;
        private int suma_wywolan = 0;
        static public int liczba_dni = 2;
        static public int liczba_godzin_w_dniu = 3;
        Algorytm_Wierzcholek zrodlo;
        Algorytm_Wierzcholek ujscie;
        Algorytm_Kolejka kolejka;
        static public int MIN_PRIO = -100;
        static public Algorytm_Wyniki wyniki = new Algorytm_Wyniki();

        List<Algorytm_Nauczyciel> lista_nauczycieli = new List<Algorytm_Nauczyciel>();
        List<Algorytm_Sala> lista_sal = new List<Algorytm_Sala>();
        List<Algorytm_Klasa> lista_klas = new List<Algorytm_Klasa>();
        List<Algorytm_Wierzcholek> lista_wierzcholkow = new List<Algorytm_Wierzcholek>();

        private void uzupelnij_wyniki()
        {
            foreach (var item in lista_klas)
            {
                item.dodaj_do_planu(wyniki);
            }
        }

        private void uzupelnij_wyniki_do_planu_awaryjnego()
        {
            foreach (var item in lista_klas)
            {
                item.dodaj_do_planu_awaryjnego(wyniki);
            }
        }

        static public Algorytm_Element_Planu[][] Init_tab()
        {
            Algorytm_Element_Planu[][] tab = new Algorytm_Element_Planu[Algorytm_Tworzenie_dla_Szkoly.liczba_dni][];
            for (int i = 0; i < Algorytm_Tworzenie_dla_Szkoly.liczba_dni; i++)
            {
                tab[i] = new Algorytm_Element_Planu[Algorytm_Tworzenie_dla_Szkoly.liczba_godzin_w_dniu];
            }
            for (int i = 0; i < Algorytm_Tworzenie_dla_Szkoly.liczba_dni; i++)
            {
                for (int j = 0; j < Algorytm_Tworzenie_dla_Szkoly.liczba_godzin_w_dniu; j++)
                {
                    tab[i][j] = new Algorytm_Element_Planu();
                    tab[i][j].Usun();
                }
            }
            return tab;
        }

        public Algorytm_Tworzenie_dla_Szkoly(int l_nauczycieli, int l_przedmiotow, int l_klas, int l_sal, int l_dni, int l_godzin)
        {
            wyniki.czysc();
            liczba_nauczycieli = l_nauczycieli;
            liczba_przedmiotow = l_przedmiotow;
            liczba_sal = l_sal;
            liczba_klas = l_klas;
            liczba_dni = l_dni + 1;
            liczba_godzin_w_dniu = l_godzin;
            kolejka = new Algorytm_Kolejka();
        }

        public void drukuj_graf(int a)
        {
            for (int i = 0; i < lista_wierzcholkow.Count; i++)
            {
                System.Console.Write(i);
                for (int q = 0; q < lista_wierzcholkow[i].krawedzie.Count; q++)
                {
                    if (a == 0 || (a == 1 && lista_wierzcholkow[i].krawedzie[q].przeplyw > 0))
                    {
                        System.Console.Write("->");
                        System.Console.Write(lista_wierzcholkow[i].krawedzie[q].cel + "(" + lista_wierzcholkow[i].krawedzie[q].przeplyw + "/" + lista_wierzcholkow[i].krawedzie[q].przepustowosc + ")");
                    }
                }
                System.Console.Write("\n");
            }
        }

        public void drukuj_nauczycieli()
        {
            p("-----drukuje nauczycieli----------");
            foreach (var item in lista_nauczycieli)
            {
                item.Print();
            }
        }

        public void drukuj_wierzcholki()
        {
            for (int i = 0; i < lista_wierzcholkow.Count; i++)
            {
                System.Console.Write(i);
                System.Console.Write(" ");
                System.Console.Write(lista_wierzcholkow[i].poziom);
                System.Console.Write(" ");
                System.Console.Write(lista_wierzcholkow[i].wartosc1);
                System.Console.Write(" ");
                System.Console.Write(lista_wierzcholkow[i].wartosc2);
                System.Console.WriteLine(" ");
            }
        }

        public void dodaj_nauczyciela(int numer_nauczyciela, int numer_preferowanej_sali, int liczba_przedmiotow, int[] tablica_przedmiotow, int liczba_przedzialow_godzin, Algorytm_Przedzial[] przedzialy)
        {
            lista_nauczycieli.Add(new Algorytm_Nauczyciel(numer_nauczyciela, numer_preferowanej_sali, liczba_przedmiotow, tablica_przedmiotow, liczba_przedzialow_godzin, przedzialy));
        }

        public void dodaj_nauczyciela(Algorytm_Nauczyciel nauczyciel)
        {
            lista_nauczycieli.Add(nauczyciel);
        }

        public void dodaj_sale(int id_sali, int liczba_przedmiotow_w_sali, int[] tablica_przedmiotow)
        {
            lista_sal.Add(new Algorytm_Sala(id_sali, liczba_przedmiotow_w_sali, tablica_przedmiotow, false));
        }

        public void dodaj_sale(Algorytm_Sala sala)
        {
            lista_sal.Add(sala);
        }

        public void dodaj_klase(int numer_klasy, int numer_preferowanej_sali, int liczba_przedmiotow, int laczna_liczba_godzin, Algorytm_Zajecia[] tablica_zajec)
        {
            lista_klas.Add(new Algorytm_Klasa(numer_klasy, numer_preferowanej_sali, liczba_przedmiotow, laczna_liczba_godzin, tablica_zajec));
        }

        public void dodaj_klase(Algorytm_Klasa klasa)
        {
            lista_klas.Add(klasa);
        }

        public void dodaj_nieobecnosc_nauczyciela(int numer_nauczyciela, Algorytm_Przedzial przedzial)
        {
            //p("dodaje niedostepnosc nauczyciela" + numer_nauczyciela);
            Daj_Nauczyciela(numer_nauczyciela).Dodaj_zly_przedzial(przedzial);
        }

        public void dodaj_niedostepnosc_sali(int numer_sali, Algorytm_Przedzial przedzial)
        {
            //p("dodaje niedostepnosc sali " + numer_sali);
            Daj_Sale(numer_sali).dodaj_zly_przedzial(przedzial);
        }

        public void Ustaw_obecny_plan(List<Algorytm_Element_wyniku> lista)
        {
            wyniki.czysc();
            Algorytm_Element_Planu element;
            int dzien, godzina;
            wyniki.Ustaw_liste(lista);
            foreach (var item in lista)
            {
                dzien = item.Dzien;
                godzina = item.Godzina;
                element = new Algorytm_Element_Planu(item.Klasa, item.Nauczyciel, item.Przedmiot, item.Sala, item.Dlugosc, item.Czy_zajecia_sa_grupowe);
                Daj_Klase(item.Klasa).Dodaj_skojarzenie(element, dzien, godzina);
                Daj_Nauczyciela(item.Nauczyciel).Dodaj_skojarzenie(element, dzien, godzina);
                Daj_Sale(item.Sala).Dodaj_skojarzenie(element, dzien, godzina, item.Dlugosc);
            }
        }

        private void Dodaj_wyniki_do_list()
        {
            List<Algorytm_Element_wyniku> lista = wyniki.Pobierz_Liste();
            Algorytm_Element_Planu element;
            foreach (var item in lista)
            {
                element = new Algorytm_Element_Planu(item.Klasa, item.Nauczyciel, item.Przedmiot, item.Sala, item.Dlugosc, item.Czy_zajecia_sa_grupowe);
                Daj_Nauczyciela(item.Nauczyciel).Dodaj_skojarzenie(element, item.Dzien, item.Godzina);
                Daj_Sale(item.Sala).Dodaj_skojarzenie(element, item.Dzien, item.Godzina, item.Dlugosc);
                Daj_Klase(item.Klasa).Dodaj_skojarzenie(element, item.Dzien, item.Godzina);
            }
        }

        public void Generuj_plan_awaryjny()
        {
            List<Algorytm_Element_Planu> lista;
            bool czy;
            bool czy_wszystko_ok = true;
            for (int i = 0; i < liczba_dni; i++)
            {
                foreach (var item in lista_nauczycieli)
                {
                    lista = item.Zwroc_przedmioty_do_zamiany(i);
                    p("licznosc listy nauczycieli " + lista.Count);
                    foreach (var item2 in lista)
                    {
                        Daj_Klase(item2.klasa).Usun_skojarzenie(item2.dzien, item2.godzina);
                        Daj_Nauczyciela(item2.nauczyciel).Usun_skojarzenie(item2.dzien, item2.godzina);
                        Daj_Sale(item2.sala).Usun_skojarzenie(item2.dzien, item2.godzina, item2.dlugosc);
                    }
                    foreach (var item2 in lista)
                    {
                        czy = Daj_Sale(item2.sala).sprawdz_czy_jest_w_zlym_przedziale(i, item2.godzina, item2.dlugosc);
                        czy_wszystko_ok = Dodaj_do_nowego_planu(item2, true, czy);
                        if (!czy_wszystko_ok) break;
                    }
                    if (!czy_wszystko_ok) break;
                }
                if (!czy_wszystko_ok) break;
                foreach (var item in lista_sal)
                {
                    lista = item.Zwroc_przedmioty_do_zamiany(i);
                    p("licznosc listy sal " + lista.Count);
                    foreach (var item2 in lista)
                    {
                        Daj_Klase(item2.klasa).Usun_skojarzenie(item2.dzien, item2.godzina);
                        Daj_Nauczyciela(item2.nauczyciel).Usun_skojarzenie(item2.dzien, item2.godzina);
                        Daj_Sale(item2.sala).Usun_skojarzenie(item2.dzien, item2.godzina, item2.dlugosc);
                    }
                    foreach (var item2 in lista)
                    {
                        czy_wszystko_ok = Dodaj_do_nowego_planu(item2, false, true);
                        if (!czy_wszystko_ok) break;
                    }
                    if (!czy_wszystko_ok) break;
                }
                if (!czy_wszystko_ok) break;
            }
            wyniki.czysc();
            uzupelnij_wyniki_do_planu_awaryjnego();
            wyniki.Czy_wszystko_poszlo_dobrze = czy_wszystko_ok;
            if (!czy_wszystko_ok) wyniki.Dodaj_komentarz("Tworzenie Planu Awaryjnego nie powiodło się...", false);
            else wyniki.Dodaj_komentarz("Plan Awaryjny wygenerowany pomyślnie...", true);
        }

        private bool Dodaj_do_nowego_planu(Algorytm_Element_Planu _elem, bool nauczyciel, bool sala)
        {
            Algorytm_Element_Planu elem = new Algorytm_Element_Planu(_elem);
            if (nauczyciel && !sala)
            {
                foreach (var item in lista_nauczycieli)
                {
                    if (item.sprawdz_czy_jest_w_zlym_przedziale(elem.dzien, elem.godzina, elem.dlugosc)) continue;
                    if (item.czy_uczy_przedmiotu(elem.przedmiot) && item.czy_moze_miec_zajecia(elem.dzien, elem.godzina, elem.dlugosc, liczba_godzin_w_dniu))
                    {
                        elem.nauczyciel = item.numer;
                        elem.czy_jest_z_awaryjnego = true;
                        Daj_Klase(elem.klasa).Dodaj_skojarzenie_do_planu_awaryjnego(elem, elem.dzien, elem.godzina);
                        Daj_Nauczyciela(item.numer).Dodaj_skojarzenie_do_planu_awaryjnego(elem, elem.dzien, elem.godzina, elem.dlugosc);
                        Daj_Sale(elem.sala).Dodaj_skojarzenie_do_planu_awaryjnego(elem, elem.dzien, elem.godzina, elem.dlugosc);

                        return true;
                    }
                }
            }
            if (nauczyciel && sala)
            {
                foreach (var item in lista_nauczycieli)
                {
                    if (item.sprawdz_czy_jest_w_zlym_przedziale(elem.dzien, elem.godzina, elem.dlugosc)) continue;
                    if (item.czy_uczy_przedmiotu(elem.przedmiot) && item.czy_moze_miec_zajecia(elem.dzien, elem.godzina, elem.dlugosc, liczba_godzin_w_dniu))
                    {
                        foreach (var item2 in lista_sal)
                        {
                            if (item2.sprawdz_czy_jest_w_zlym_przedziale(elem.dzien, elem.godzina, elem.dlugosc)) continue;
                            if (!item2.Czy_sala_jest_wolna(elem.dzien, elem.godzina, elem.dlugosc, liczba_godzin_w_dniu)) continue;
                            if (!Daj_Nauczyciela(item.numer).czy_moze_miec_zajecia(elem.dzien, elem.godzina, elem.dlugosc, liczba_godzin_w_dniu)) continue;
                            elem.nauczyciel = item.numer;
                            elem.sala = item2.numer;
                            elem.czy_jest_z_awaryjnego = true;
                            Daj_Klase(elem.klasa).Dodaj_skojarzenie_do_planu_awaryjnego(elem, elem.dzien, elem.godzina);
                            Daj_Nauczyciela(elem.nauczyciel).Dodaj_skojarzenie_do_planu_awaryjnego(elem, elem.dzien, elem.godzina, elem.dlugosc);
                            Daj_Sale(elem.sala).Dodaj_skojarzenie_do_planu_awaryjnego(elem, elem.dzien, elem.godzina, elem.dlugosc);
                            return true;
                        }
                    }
                }
            }
            if (!nauczyciel && sala)
            {
                foreach (var item in lista_sal)
                {
                    if (item.sprawdz_czy_jest_w_zlym_przedziale(elem.dzien, elem.godzina, elem.dlugosc)) continue;
                    if (!item.Czy_sala_jest_wolna(elem.dzien, elem.godzina, elem.dlugosc, liczba_godzin_w_dniu)) continue;
                    elem.sala = item.numer;
                    elem.czy_jest_z_awaryjnego = true;
                    Daj_Klase(elem.klasa).Dodaj_skojarzenie_do_planu_awaryjnego(elem, elem.dzien, elem.godzina);
                    Daj_Nauczyciela(elem.nauczyciel).Dodaj_skojarzenie_do_planu_awaryjnego(elem, elem.dzien, elem.godzina, elem.dlugosc);
                    Daj_Sale(elem.sala).Dodaj_skojarzenie_do_planu_awaryjnego(elem, elem.dzien, elem.godzina, elem.dlugosc);
                    return true;
                }
            }
            return false;
        }

        public void start()
        {
            tworzenie_wierzcholkow();
            go_go();
            uzupelnij_wyniki();
        }

        private void go_go()
        {
            bool dzialaj = true;
            int licznik = -1;
            while (dzialaj)
            {
                licznik++;
                Console.WriteLine("" + licznik + "/" + suma_wywolan);
                foreach (var item in lista_wierzcholkow)
                {
                    item.czysc_zmienne();
                }
                dzialaj = znajdz_sciezke(0);
                if (!dzialaj)
                {
                    foreach (var krawedz in lista_wierzcholkow[0].krawedzie)
                    {
                        if (krawedz.pelna()) continue;
                        foreach (var item in lista_wierzcholkow)
                        {
                            item.czysc_zmienne();
                        }
                        lista_wierzcholkow[krawedz.cel].odwiedzony = true;
                        lista_wierzcholkow[krawedz.cel].krawedz_dodajaca = krawedz;
                        dzialaj = znajdz_sciezke(krawedz.cel);
                        if (dzialaj) break;
                    }
                }
            }
            p(licznik + "/" + suma_wywolan);
            if (licznik != suma_wywolan)
                wyniki.Dodaj_komentarz("nie udalo sie utworzyc calego planu", false);
            else
                wyniki.Dodaj_komentarz("Udalo sie ", true);
        }

        private bool znajdz_sciezke(int numereczek)
        {
            List<int> lista_pom = new List<int>();
            kolejka.wyczysc();
            kolejka.dodaj(numereczek, 1);
            int wierz;
            bool wsparcie = false;
            int cel, prio;
            Algorytm_Krawedz kraw;
            Algorytm_Wierzcholek wWierz, wCel;
            bool dzialaj = true;
            bool klasa_moze, nauczyciel_moze;
            int p1, p2, p3;
            lista_wierzcholkow[0].odwiedzony = true;
            while (dzialaj && !kolejka.pusta())
            {
                wierz = kolejka.zdejmij();
                wWierz = lista_wierzcholkow[wierz];
                p1 = wWierz.poziom;

                if (p1 == 2 && Daj_Klase(lista_wierzcholkow[wWierz.A].wartosc1).Czy_zajecia_sa_grupowe(wWierz.wartosc2))
                {
                    wsparcie = false;
                    foreach (var krawedz in wWierz.krawedzie)
                    {
                        if (krawedz.pelna()) continue;
                        cel = krawedz.cel;
                        wCel = lista_wierzcholkow[cel];
                        if (wCel.odwiedzony) continue;
                        wCel.zmien_liste(wWierz.obecnie_rozwazane);
                        p2 = wCel.poziom;
                        if (p2 != 3) continue;

                        wCel.ustaw_BC(wierz, cel);

                        nauczyciel_moze = !Daj_Nauczyciela(wWierz.wartosc1).czy_ma_juz_jakies_zajecia(wCel.wartosc2, wCel.wartosc3);
                        if (nauczyciel_moze) nauczyciel_moze = !wCel.Sprawdz_czy_jest_w_rozwazanych(2, wWierz.wartosc1, wCel.wartosc2, wCel.wartosc3, -1);
                        if (!nauczyciel_moze) nauczyciel_moze = wCel.Sprawdz_czy_jest_w_rozwazanych(2, wWierz.wartosc1, wCel.wartosc2, wCel.wartosc3, 1);
                        if (!nauczyciel_moze) continue;
                        if (wCel.skojarzenie1 == lista_wierzcholkow[wWierz.A].wartosc1 && wCel.skojarzenie2 != wWierz.wartosc2)
                        {
                            if (Daj_Klase(lista_wierzcholkow[wWierz.A].wartosc1).Czy_jest_miejsce_na_zajecia_grupowe(wCel.wartosc2, wCel.wartosc3))
                            {
                                wCel.krawedz_dodajaca = krawedz;
                                ujscie.krawedz_dodajaca = new Algorytm_Krawedz(cel, 0, 0);
                                dzialaj = false;
                                wsparcie = true;
                                break;
                            }
                        }
                    }
                }

                if (wsparcie) continue;

                foreach (var krawedz in wWierz.krawedzie)
                {
                    if (krawedz.pelna()) continue;
                    cel = krawedz.cel;
                    wCel = lista_wierzcholkow[cel];
                    if (wCel.odwiedzony) continue;
                    if (cel == ujscie.pozycja_w_liscie)
                    {
                        dzialaj = false;
                        ujscie.krawedz_dodajaca = krawedz;
                        break;
                    }
                    wCel.zmien_liste(wWierz.obecnie_rozwazane);
                    p2 = wCel.poziom;
                    bool pisac = false;
                    if (p1 == 1 && p2 == 2)
                    {
                        if (wWierz.wartosc1 == 1 && wCel.wartosc2 == 6)
                        {
                            p("sciezka z klasy " + wWierz.wartosc1 + " do przedmiotu " + wCel.wartosc1);
                            pisac = true;
                        }
                        wCel.ustaw_ABC(wierz, cel, -1);
                    }
                    else
                        if (p1 == 2 && p2 == 3)
                        {
                            wCel.ustaw_BC(wierz, cel);

                            klasa_moze = Daj_Klase(lista_wierzcholkow[wWierz.A].wartosc1).czy_moga_byc_zajecia(wCel.wartosc2, wCel.wartosc3);
                            if (klasa_moze) klasa_moze = !wCel.Sprawdz_czy_jest_w_rozwazanych(1, lista_wierzcholkow[wWierz.A].wartosc1, wCel.wartosc2, wCel.wartosc3, -1);
                            if (!klasa_moze) klasa_moze = wCel.Sprawdz_czy_jest_w_rozwazanych(1, lista_wierzcholkow[wWierz.A].wartosc1, wCel.wartosc2, wCel.wartosc3, 1);

                            nauczyciel_moze = !Daj_Nauczyciela(wWierz.wartosc1).czy_ma_juz_jakies_zajecia(wCel.wartosc2, wCel.wartosc3);
                            if (nauczyciel_moze) nauczyciel_moze = !wCel.Sprawdz_czy_jest_w_rozwazanych(2, wWierz.wartosc1, wCel.wartosc2, wCel.wartosc3, -1);
                            if (!nauczyciel_moze) nauczyciel_moze = wCel.Sprawdz_czy_jest_w_rozwazanych(2, wWierz.wartosc1, wCel.wartosc2, wCel.wartosc3, 1);

                            if (wCel.skojarzenie1 != -1)
                            {
                                if (wCel.skojarzenie1 != wWierz.A)
                                {
                                    if (!klasa_moze) continue;
                                }
                                if (lista_wierzcholkow[wCel.skojarzenie2].wartosc1 != wWierz.wartosc1)
                                {
                                    if (!nauczyciel_moze) continue;
                                }
                                lista_wierzcholkow[cel].dodaj_do_rozwazanych(1, lista_wierzcholkow[wWierz.A].wartosc1,
                                wCel.wartosc2, wCel.wartosc3, -1);
                                lista_wierzcholkow[cel].dodaj_do_rozwazanych(2, wWierz.wartosc1,
                                wCel.wartosc2, wCel.wartosc3, -1);
                            }
                            else
                            {
                                if (!klasa_moze || !nauczyciel_moze) continue;
                            }
                        }
                        else
                            if (p1 == 3 && p2 == 2)
                            {
                                lista_wierzcholkow[cel].ustaw_ABC(wWierz.skojarzenie1, cel, -1);

                                lista_wierzcholkow[cel].dodaj_do_rozwazanych(1, lista_wierzcholkow[wWierz.skojarzenie1].wartosc1,
                                    lista_wierzcholkow[wierz].wartosc2, lista_wierzcholkow[wierz].wartosc3, 1);
                                lista_wierzcholkow[cel].dodaj_do_rozwazanych(2, lista_wierzcholkow[wWierz.skojarzenie2].wartosc1,
                                    lista_wierzcholkow[wierz].wartosc2, lista_wierzcholkow[wierz].wartosc3, 1);
                            }
                            else
                                if (p1 == 2 && p2 == 1)
                                {
                                    lista_wierzcholkow[cel].ustaw_ABC(-1, -1, -1);
                                }

                    prio = oblicz_priorytet(lista_wierzcholkow[wierz], lista_wierzcholkow[cel]);
                    if (pisac) p("prio = " + prio);
                    if (prio == MIN_PRIO) continue;
                    lista_wierzcholkow[cel].odwiedzony = true;
                    lista_wierzcholkow[cel].krawedz_dodajaca = krawedz;
                    // p("Wierz: " + wierz + " wrzuca Cel: " + cel);
                    kolejka.dodaj(cel, prio);
                }
            }
            if (dzialaj) return false;
            lista_pom.Add(ujscie.pozycja_w_liscie);
            kraw = ujscie.krawedz_dodajaca;
            wierz = kraw.skad;
            while (wierz != 0)
            {
                lista_pom.Add(wierz);
                kraw = lista_wierzcholkow[wierz].krawedz_dodajaca;
                wierz = kraw.skad;
            }
            lista_pom.Reverse();

            for (int i = 0; i < lista_pom.Count; i++)
            {
                Console.Write(lista_pom[i] + " ");
            }
            p("  --------------------------------");
            p1 = -1; p2 = -1; p3 = -1;
            Algorytm_Wierzcholek wierzch;
            for (int i = 0; i < lista_pom.Count; i++)
            {
                wierzch = lista_wierzcholkow[lista_pom[i]];
                wierzch.krawedz_dodajaca.pusc_przeplyw();
                if (wierzch.poziom == 1)
                {
                    p1 = lista_pom[i];
                }
                else
                    if (wierzch.poziom == 2)
                    {
                        p2 = lista_pom[i];
                    }
                    else
                        if (wierzch.poziom == 3)
                        {
                            p3 = lista_pom[i];
                            p1 = dodaj_skojarzenie(p1, p2, p3);
                        }
            }
            return true;
        }

        private int dodaj_skojarzenie(int w1, int w2, int w3)
        {
            int dzien = lista_wierzcholkow[w3].wartosc2;
            int godzina = lista_wierzcholkow[w3].wartosc3;
            int pom1 = w1;
            bool czy = Daj_Klase(lista_wierzcholkow[w1].wartosc1).Czy_zajecia_sa_grupowe(lista_wierzcholkow[w2].wartosc2);
            bool czy2 = false;
            if (lista_wierzcholkow[w3].skojarzenie1 != -1)
            {
                czy2 = Daj_Klase(lista_wierzcholkow[lista_wierzcholkow[w3].skojarzenie1].wartosc1).Czy_zajecia_sa_grupowe(lista_wierzcholkow[lista_wierzcholkow[w3].skojarzenie2].wartosc2);
                if (!czy || !czy2)
                {
                    pom1 = lista_wierzcholkow[w3].skojarzenie1;
                    usun_skojarzenie(w1, dzien, godzina);
                    usun_skojarzenie(w2, dzien, godzina);
                    lista_wierzcholkow[w3].skojarzenie1 = -1;
                }
            }
            Algorytm_Element_Planu element = new Algorytm_Element_Planu(lista_wierzcholkow[w1].wartosc1,
                lista_wierzcholkow[w2].wartosc1, lista_wierzcholkow[w2].wartosc2,
                lista_wierzcholkow[w3].wartosc1, 1, czy);
            Daj_Klase(lista_wierzcholkow[w1].wartosc1).Dodaj_skojarzenie(element, dzien, godzina);
            Daj_Nauczyciela(lista_wierzcholkow[w2].wartosc1).Dodaj_skojarzenie(element, dzien, godzina);
            lista_wierzcholkow[w3].skojarzenie1 = w1;
            lista_wierzcholkow[w3].skojarzenie2 = w2;
            if (czy && czy2) lista_wierzcholkow[w3].podwojny = true;
            return pom1;
        }

        private void usun_skojarzenie(int w1, int dzien, int godz)
        {
            if (lista_wierzcholkow[w1].poziom == 1)
            {
                Daj_Klase(lista_wierzcholkow[w1].wartosc1).Usun_skojarzenie(dzien, godz);
            }
            else
                if (lista_wierzcholkow[w1].poziom == 2)
                {
                    Daj_Nauczyciela(lista_wierzcholkow[w1].wartosc1).Usun_skojarzenie(dzien, godz);
                }
        }

        private int oblicz_priorytet(Algorytm_Wierzcholek a, Algorytm_Wierzcholek b)
        {
            int poziom1 = a.poziom;
            int poziom2 = b.poziom;
            int pom, pom2;
            if (poziom1 == 0 || poziom2 == 4) return 100;
            if (poziom1 == 1 && poziom2 == 2)
            {
                if (Daj_Klase(a.wartosc1).czy_sa_miejsca(b.wartosc2))
                {
                    pom = Daj_Klase(a.wartosc1).numer_prowdzacego_zajecia(b.wartosc2);
                    if (pom == -1) return 0;
                    if (pom == b.wartosc1) return 4;
                    return -4;
                }
                else
                {
                    return MIN_PRIO;
                }
            }
            if (poziom1 == 2 && poziom2 == 3)
            {
                pom = Daj_Klase(lista_wierzcholkow[a.A].wartosc1).policz_priotytet(b.wartosc2, b.wartosc3);
                if (Daj_Klase(lista_wierzcholkow[a.A].wartosc1).ilosc_zajec_w_danym_dniu(b.wartosc2, a.wartosc2) > 0) pom = -4;
                pom2 = Daj_Nauczyciela(a.wartosc1).policz_priorytet(b.wartosc2, b.wartosc3);
                if (pom == MIN_PRIO || pom2 == MIN_PRIO) return MIN_PRIO;
                return pom + pom2;
            }
            if (poziom1 == 3 && poziom2 == 2)
            {
                pom = Daj_Klase(lista_wierzcholkow[b.A].wartosc1).policz_priorytet_usuniecia(a.wartosc2, a.wartosc3);
                pom2 = Daj_Nauczyciela(b.wartosc1).policz_priorytet_usuniecia(a.wartosc2, a.wartosc3);
                return pom + pom2;
            }
            if (poziom1 == 2 && poziom2 == 1)
            {
                if (b.C == -1) return MIN_PRIO;
                if (Daj_Klase(b.wartosc1).liczba_zajec_z_przedmiotu(a.wartosc2) == 1) return 0;
                pom = Daj_Klase(b.wartosc1).numer_prowdzacego_zajecia(a.wartosc2);
                if (pom != a.wartosc1) return -6;
                else return -3;
            }
            return MIN_PRIO;
        }

        private void utworz_zrodlo()
        {
            zrodlo = new Algorytm_Wierzcholek(0);
            lista_wierzcholkow.Add(zrodlo);
        }

        private void utworz_wierzcholki_klas()
        {
            for (int i = 0; i < lista_klas.Count; i++)
            {
                lista_wierzcholkow.Add(new Algorytm_Wierzcholek(1, i, lista_klas[i].numer, lista_klas[i].laczna_liczba_godzin));
            }
        }

        private void utworz_wierzcholki_sal()
        {
            for (int i = 0; i < lista_sal.Count; i++)
            {
                for (int dzien = 0; dzien < liczba_dni; dzien++)
                {
                    for (int godzina = 0; godzina < liczba_godzin_w_dniu; godzina++)
                    {
                        lista_wierzcholkow.Add(new Algorytm_Wierzcholek(3, i, lista_sal[i].numer, dzien, godzina));
                    }
                }
            }
        }

        private void utworz_wierzcholki_nauczycieli()
        {
            for (int i = 0; i < lista_nauczycieli.Count; i++)
            {
                for (int j = 0; j < lista_nauczycieli[i].liczba_przedmiotow; j++)
                {
                    lista_wierzcholkow.Add(new Algorytm_Wierzcholek(2, i, lista_nauczycieli[i].numer, lista_nauczycieli[i].przedmioty[j]));
                }
            }
        }

        private void utworz_ujscie()
        {
            ujscie = new Algorytm_Wierzcholek(4);
            ujscie.pozycja_w_liscie = lista_wierzcholkow.Count;
            lista_wierzcholkow.Add(ujscie);
        }

        private void utworz_krawedzie_zrodlo_klasy()
        {
            suma_wywolan = 0;
            int numer_zrodla = 0;
            Algorytm_Krawedz krawedz;
            for (int i = 0; i < lista_wierzcholkow.Count; i++)
            {
                if (lista_wierzcholkow[i].poziom == 0)
                {
                    numer_zrodla = i;
                    break;
                }
            }
            for (int i = 0; i < lista_wierzcholkow.Count; i++)
            {
                if (lista_wierzcholkow[i].poziom == 1)
                {
                    krawedz = new Algorytm_Krawedz(numer_zrodla, i, lista_wierzcholkow[i].wartosc2);
                    zrodlo.krawedzie.Add(krawedz);
                    suma_wywolan += lista_wierzcholkow[i].wartosc2;
                }
            }
        }

        private void utworz_krawedzie_klasy_nauczyciele()
        {
            List<Algorytm_Zajecia> zajecia;

            for (int i = 0; i < lista_wierzcholkow.Count; i++)
            {
                if (lista_wierzcholkow[i].poziom == 1)
                {
                    for (int j = 0; j < lista_wierzcholkow.Count; j++)
                    {
                        if (lista_wierzcholkow[j].poziom == 2)
                        {
                            zajecia = lista_klas[lista_wierzcholkow[i].pozycja_w_liscie].zajecia;
                            for (int q = 0; q < zajecia.Count; q++)
                            {
                                if (lista_wierzcholkow[j].wartosc2 == zajecia[q].numer_przedmiotu)
                                {
                                    Algorytm_Krawedz krawedz = new Algorytm_Krawedz(i, j, zajecia[q].maksymalna_liczba_godzin);
                                    Algorytm_Krawedz krawedz2 = new Algorytm_Krawedz(j, i, 0, krawedz);
                                    krawedz.dodaj_krawedz_przeciwna(krawedz2);
                                    lista_wierzcholkow[i].krawedzie.Add(krawedz);
                                    lista_wierzcholkow[j].krawedzie.Add(krawedz2);
                                }
                            }
                        }
                    }
                }
            }
        }

        private void utworz_krawedzie_nauczyciele_sale()
        {
            for (int i = 0; i < lista_wierzcholkow.Count; i++)
            {
                if (lista_wierzcholkow[i].poziom == 2)
                {
                    for (int j = 0; j < lista_wierzcholkow.Count; j++)
                    {
                        if (lista_wierzcholkow[j].poziom == 3)
                        {
                            if (lista_sal[lista_wierzcholkow[j].pozycja_w_liscie].przedmioty.Contains(lista_wierzcholkow[i].wartosc2))
                            {
                                Algorytm_Wierzcholek w = lista_wierzcholkow[j];
                                if (lista_nauczycieli[lista_wierzcholkow[i].pozycja_w_liscie].czy_jest_dostepny(w.wartosc2, w.wartosc3, 1))
                                {
                                    Algorytm_Krawedz krawedz = new Algorytm_Krawedz(i, j, 1);
                                    Algorytm_Krawedz krawedz2 = new Algorytm_Krawedz(j, i, 0, krawedz);
                                    krawedz.dodaj_krawedz_przeciwna(krawedz2);
                                    lista_wierzcholkow[i].krawedzie.Add(krawedz);
                                    lista_wierzcholkow[j].krawedzie.Add(krawedz2);
                                }
                            }
                        }
                    }
                }
            }
        }

        private void utworz_krawedzie_sale_ujscie()
        {
            Algorytm_Wierzcholek ujscie;
            int numer_ujscia = 0;
            for (int i = 0; i < lista_wierzcholkow.Count; i++)
            {
                if (lista_wierzcholkow[i].poziom == 4)
                {
                    ujscie = lista_wierzcholkow[i];
                    numer_ujscia = i;
                }
            }
            for (int i = 0; i < lista_wierzcholkow.Count; i++)
            {
                if (lista_wierzcholkow[i].poziom == 3)
                {
                    lista_wierzcholkow[i].krawedzie.Add(new Algorytm_Krawedz(i, numer_ujscia, 1));
                }
            }
        }

        private void tworzenie_wierzcholkow()
        {
            utworz_zrodlo();
            utworz_wierzcholki_klas();
            utworz_wierzcholki_nauczycieli();
            utworz_wierzcholki_sal();
            utworz_ujscie();
            utworz_krawedzie_zrodlo_klasy();
            utworz_krawedzie_klasy_nauczyciele();
            utworz_krawedzie_nauczyciele_sale();
            utworz_krawedzie_sale_ujscie();
        }

        static public void p(int a)
        {
            System.Console.WriteLine(a);
        }

        public Algorytm_Para Test()
        {
            Algorytm_Para para = new Algorytm_Para(1, 0);
            List<Algorytm_Para> tab = new List<Algorytm_Para>();
            List<Algorytm_Para> tab2 = new List<Algorytm_Para>();
            int suma_godzin = 0;
            int suma_godz_nauczycieli = 0;
            foreach (var item in lista_klas)
            {
                foreach (var item2 in item.zajecia)
                {
                    tab.Add(new Algorytm_Para(item2.numer_przedmiotu, item2.maksymalna_liczba_godzin));
                    suma_godzin += item2.maksymalna_liczba_godzin;
                }
            }
            tab.Sort(Algorytm.Algorytm_Kolejka.ComparePara2);
            int a = -1, sum = 0;

            foreach (var item in tab)
            {
                if (a == -1)
                {
                    a = item.numer;
                    sum = item.prio;
                    continue;
                }
                if (a != item.numer)
                {
                    tab2.Add(new Algorytm_Para(a, sum));
                    a = item.numer;
                    sum = item.prio;
                }
                else
                {
                    sum += item.prio;
                }
            }
            tab2.Add(new Algorytm_Para(a, sum));
            tab.Clear();
            foreach (var item in lista_nauczycieli)
            {
                foreach (var item2 in item.przedmioty)
                {
                    tab.Add(new Algorytm_Para(item2, -item.laczna_dostepnosc));
                    suma_godz_nauczycieli += item.laczna_dostepnosc;
                }
            }
            if (suma_godzin > suma_godz_nauczycieli) return new Algorytm_Para(0, 0);
            a = -1; sum = 0;

            foreach (var item in tab)
            {
                if (a == -1)
                {
                    a = item.numer;
                    sum = item.prio;
                    continue;
                }
                if (a != item.numer)
                {
                    tab2.Add(new Algorytm_Para(a, sum));
                    a = item.numer;
                    sum = item.prio;
                }
                else
                {
                    sum += item.prio;
                }
            }
            tab2.Add(new Algorytm_Para(a, sum));
            tab2.Sort(Algorytm_Kolejka.ComparePara2);
            tab.Clear();
            a = -1; sum = 0;

            foreach (var item in tab2)
            {
                if (a == -1)
                {
                    a = item.numer;
                    sum = item.prio;
                    continue;
                }
                if (a != item.numer)
                {
                    tab.Add(new Algorytm_Para(a, sum));
                    a = item.numer;
                    sum = item.prio;
                }
                else
                {
                    sum += item.prio;
                }
            }
            tab.Add(new Algorytm_Para(a, sum));
            foreach (var item in tab)
            {
                if (item.prio > 0) return new Algorytm_Para(-1, item.numer);
            }
            bool zle = false;
            foreach (var item in tab)
            {
                zle = true;
                foreach (var item2 in lista_sal)
                {
                    foreach (var item3 in item2.przedmioty)
                    {
                        if (item3 == item.numer) { zle = false; break; }
                    }
                    if (!zle) break;
                }
                if (zle) return new Algorytm_Para(-2, item.numer);
            }

            return para;
        }

        static public void p(string a)
        {
            System.Console.WriteLine(a);
        }

        private Algorytm_Sala Daj_Sale(int nr)
        {
            Algorytm_Sala sal = new Algorytm_Sala();
            foreach (var item in lista_sal)
            {
                if (item.numer == nr)
                    return item;
            }
            return sal;
        }

        private Algorytm_Nauczyciel Daj_Nauczyciela(int nr)
        {
            Algorytm_Nauczyciel nau = new Algorytm_Nauczyciel();
            foreach (var item in lista_nauczycieli)
            {
                if (item.numer == nr)
                    return item;
            }
            return nau;
        }

        private Algorytm_Klasa Daj_Klase(int nr)
        {
            Algorytm_Klasa klas = new Algorytm_Klasa();
            foreach (var item in lista_klas)
            {
                if (item.numer == nr)
                    return item;
            }
            return klas;
        }

        public Algorytm_Wyniki Pobierz_Plan()
        {
            Algorytm_Wyniki wyn = new Algorytm_Wyniki(wyniki);
            return wyn;
        }

        private static void Maine(string[] args)
        {
            p("start");
            int nr, prefnr, lprzed, lprzedzial, lgodz;
            int[] pomtab;
            Algorytm_Przedzial[] lista;
            Algorytm_Zajecia[] lista_zajec;
            StreamReader plik = new System.IO.StreamReader("e:\\plik2.txt");
            string sLine = "";
            sLine = plik.ReadLine();
            string[] tab = sLine.Split(' ');
            int liczba_nauczycieli = int.Parse(tab[0]);
            int liczba_przedmiotow = int.Parse(tab[1]);
            int liczba_sal = int.Parse(tab[2]);
            int liczba_klas = int.Parse(tab[3]);
            int ll_dni = int.Parse(tab[4]);
            int ll_godz = int.Parse(tab[5]);
            Algorytm_Tworzenie_dla_Szkoly A = new Algorytm_Tworzenie_dla_Szkoly(liczba_nauczycieli, liczba_przedmiotow, liczba_klas, liczba_sal, ll_dni, ll_godz);
            Algorytm_Tworzenie_dla_Szkoly B = new Algorytm_Tworzenie_dla_Szkoly(liczba_nauczycieli, liczba_przedmiotow, liczba_klas, liczba_sal, ll_dni, ll_godz);

            for (int i = 0; i < liczba_nauczycieli; i++)
            {
                sLine = plik.ReadLine();
                tab = sLine.Split(' ');
                nr = int.Parse(tab[0]);
                prefnr = int.Parse(tab[1]);
                lprzed = int.Parse(tab[2]);
                pomtab = new int[lprzed];
                for (int q = 0; q < lprzed; q++)
                {
                    pomtab[q] = int.Parse(tab[3 + q]);
                }
                lprzedzial = int.Parse(tab[3 + lprzed]);
                lista = new Algorytm_Przedzial[lprzedzial];
                for (int q = 0; q < lprzedzial; q++)
                {
                    lista[q] = new Algorytm_Przedzial(int.Parse(tab[4 + lprzed + q * 3]), int.Parse(tab[5 + lprzed + q * 3]), int.Parse(tab[6 + lprzed + q * 3]));
                }
                A.dodaj_nauczyciela(nr, prefnr, lprzed, pomtab, lprzedzial, lista);
                B.dodaj_nauczyciela(nr, prefnr, lprzed, pomtab, lprzedzial, lista);
            }
            for (int i = 0; i < liczba_sal; i++)
            {
                sLine = plik.ReadLine();
                tab = sLine.Split(' ');
                nr = int.Parse(tab[0]);
                lprzed = int.Parse(tab[1]);
                pomtab = new int[lprzed];
                for (int q = 0; q < lprzed; q++)
                {
                    pomtab[q] = int.Parse(tab[2 + q]);
                }
                A.dodaj_sale(nr, lprzed, pomtab);
                B.dodaj_sale(nr, lprzed, pomtab);
            }
            for (int i = 0; i < liczba_klas; i++)
            {
                sLine = plik.ReadLine();
                tab = sLine.Split(' ');
                nr = int.Parse(tab[0]);
                prefnr = int.Parse(tab[1]);
                lprzed = int.Parse(tab[2]);
                lgodz = int.Parse(tab[3]);
                lista_zajec = new Algorytm_Zajecia[lprzed];
                for (int q = 0; q < lprzed; q++)
                {
                    lista_zajec[q] = new Algorytm_Zajecia(int.Parse(tab[4 + q * 3]), int.Parse(tab[5 + q * 3]), int.Parse(tab[6 + q * 3]));
                }

                A.dodaj_klase(nr, prefnr, lprzed, lgodz, lista_zajec);
                B.dodaj_klase(nr, prefnr, lprzed, lgodz, lista_zajec);
            }

            plik.Close();
            A.start();
            //A.drukuj_wierzcholki();
            //A.drukuj_graf(0);
            //A.drukuj_graf(1);
            p("-------------------------");
            List<Algorytm_Element_wyniku> wyn = Algorytm_Tworzenie_dla_Szkoly.wyniki.Pobierz_Liste();
            wyniki.Drukuj();
            B.Ustaw_obecny_plan(wyn);
            B.dodaj_nieobecnosc_nauczyciela(2, new Algorytm_Przedzial(1, 3, 4));
            B.Generuj_plan_awaryjny();
            p("-------------------------");
            wyniki.Drukuj();
            p("koniec");
            Console.ReadKey();
        }
    }
}